<?php
namespace Protocols;
class EnDp
{
    /**
     * 检查包的完整性
     * 如果能够得到包长，则返回包的在buffer中的长度，否则返回0继续等待数据
     * 如果协议有问题，则可以返回false，当前客户端连接会因此断开
     * 1	CONN_REQ：  连接建立请求    C(client)->S(server)
     * 2	CONN_RESP： 连接建立响应    S->C
     * 4	CONN_CLOSE：连接关闭        S->C
     * 8	SAVE_DATA： 存储            C->S
     * 9	SAVE_RESP： 存储确认        S->C
     * 10	CMD_REQ：   命令请求        S->C
     * 11	CMD_RESP：	命令响应        C->S
     * 12	PING_REQ: 心跳请求          C->S
     * 13	PING_RESP: 心跳响应         S->C
     * @param string $buffer
     * @return int
     */
    public static function input($buffer)
    {
        //每8字节为一组数据
        if(strlen($buffer)%8 != 0)
        {
            // 不够8字节，返回0继续等待数据
            return 0;
        }
        if(strlen($buffer)< 16 ){
            return 0;
        }
        $result0 = substr($buffer,8,1); //长度1字节
        $len = intval(base_convert(substr($buffer,9,7),2,10));
        if($result0 == '1'){ //长度1字节高位验证
            if(strlen($buffer)< 24 ){
                return 0;
            }
            $result1 = substr($buffer,16,1);//长度2字节
            $len += intval(base_convert(substr($buffer,17,7),2,10))*128;
            if($result1 == '1'){//长度2字节高位验证
                if(strlen($buffer)< 32 ){
                    return 0;
                }
                $result2 = substr($buffer,24,1);//长度3字节
                $len += intval(base_convert(substr($buffer,25,7),2,10))*128*128;
                if($result2 == '1'){//长度3字节高位验证
                    if(strlen($buffer)< 40 ){
                        return 0;
                    }
                    $result3 = substr($buffer,32,1);//长度4字节
                    $len += intval(base_convert(substr($buffer,33,7),2,10))*128*128*128;
                }
            }
            
        }
        return $len*8;
    }

    /**
     * 打包，当向客户端发送数据的时候会自动调用
     * @param string $buffer
     * @return string
     */
    public static function encode($jsonData)
    {
        $data = json_decode($jsonData,true);
        $result ="";
        switch ($data['type']) {
            
            case '2': //连接响应
                $byte1 =sprintf('%04d0000',base_convert('2',10,2));
                
                break;
            case '4': //连接关闭
                $byte1 =sprintf('%04d0000',base_convert('4',10,2));
                break;
            case '9'://存储确认
                $byte1 =sprintf('%04d0000',base_convert('9',10,2));
                # code...
                break;
            case '10': //命令请求
                $byte1 =sprintf('%04d0000',base_convert('10',10,2));
                break;
            case '13': //心跳响应
                $byte1 =sprintf('%04d0000',base_convert('13',10,2));
                $byte2 =sprintf('%08d',base_convert($data['data'],10,2));
                $result = $byte1.$byte2;
                break;
        }
        return $result;
    }

    /**
     * 解包，当接收到的数据字节数等于input返回的值（大于0的值）自动调用
     * 并传递给onMessage回调函数的$data参数
     * @param string $buffer
     * @return string
     */
    public static function decode($buffer)
    {
        $type = base_convert(substr($buffer,0,4),2,10);
        switch ($type) {
            case '1': //建立连接
                $data = [];
                $data['type'] = $type;
                $len = base_convert(substr($buffer,8,8),2,10); //字节长度
                $result =[];
                for ($i=0; $i < $len ; $i++) { 
                  $result[] =substr($buffer,16+($i*8),8);
                }
                //协议
                $versionLong =  base_convert(strval(base_convert($result[0],2,10)).sprintf('%02d',base_convert($result[1],2,10)),16,10);
                $data['protocol'] = '';
                for ($i=0; $i < intval($versionLong); $i++) { 
                    $data['protocol'].=self::asc2char($result[2+$i]);
                }
                //版本
                $data['version'] = '';
                $data['version'] = base_convert($result[2 + intval($versionLong)],2,10);
                //连接标志
                $data['flag'] = intval($result[3+intval($versionLong)]);
                //保持连接时间
                $data['time_long'] = base_convert(strval(base_convert($result[4+intval($versionLong)],2,10)).sprintf('%02d',base_convert($result[5+intval($versionLong)],2,10)),16,10);
                //设备ID
                $data['engine_id'] = '';
                $engineLength = base_convert(strval(base_convert($result[6+intval($versionLong)],2,10)).sprintf('%02d',base_convert($result[7+intval($versionLong)],2,10)),16,10);
                $engineLength1 = 8+intval($versionLong);
                for ($i=0; $i < intval($engineLength); $i++) { 
                   $data['engine_id'] .= self::asc2char($result[$engineLength1+$i]);
                }
                //鉴权信息 api-key
                $data['api_key'] = '';
                $tokenLen = base_convert(strval(base_convert($result[9+intval($engineLength)+intval($versionLong)],2,10)).sprintf('%02d',base_convert($result[10+intval($engineLength)+intval($versionLong)],2,10)),16,10);
                $tokenLen1 = 10+intval($engineLength)+intval($versionLong);
                for ($i=0; $i < $tokenLen; $i++) { 
                    $data['api_key'] .= self::asc2char($result[$tokenLen1+$i]);
                }
                return json_encode($data);
                break;            
            case '8': //存储
                $result = [];
                for ($i=0; $i < strlen($buffer) ; $i += 8) { 
                    $result[] = substr($buffer, $i, 8);
                }

                break;
            case '11': //命令确认
                # code...
                break;
            case '12': //心跳请求
                $data = [
                    'type'=>12,
                    'data'=>0,
                ];
                return json_encode($data);
                break;
        }
    }
    //字符解包 CHAR TO ASCII码
    public static function char2asc($code){
        $num = ord($code);
        return sprintf('%08d',base_convert($num,10,2));
    } 
    //字符打包 ASCII码 TO CHAR
    public static function asc2char($code){
        $num = base_convert($code,2,10);
        chr($num);
    }
}